/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.wisii.wisedoc.banding.io.dtd;

import java.io.IOException;
import java.io.Reader;
import java.util.Hashtable;
import java.util.Stack;

/**
 * 类功能描述：
 * 
 * 作者：zhongyajun 创建日期：2008.10.23
 */

class Scanner
{

	public static final TokenType LTQUES = new TokenType(0, "LTQUES");

	public static final TokenType IDENTIFIER = new TokenType(1, "IDENTIFIER");

	public static final TokenType EQUAL = new TokenType(2, "EQUAL");

	public static final TokenType LPAREN = new TokenType(3, "LPAREN");

	public static final TokenType RPAREN = new TokenType(4, "RPAREN");

	public static final TokenType COMMA = new TokenType(5, "COMMA");

	public static final TokenType STRING = new TokenType(6, "STRING");

	public static final TokenType QUESGT = new TokenType(7, "QUESGT");

	public static final TokenType LTBANG = new TokenType(8, "LTBANG");

	public static final TokenType GT = new TokenType(9, "GT");

	public static final TokenType PIPE = new TokenType(10, "PIPE");

	public static final TokenType QUES = new TokenType(11, "QUES");

	public static final TokenType PLUS = new TokenType(12, "PLUS");

	public static final TokenType ASTERISK = new TokenType(13, "ASTERISK");

	public static final TokenType LT = new TokenType(14, "LT");

	public static final TokenType EOF = new TokenType(15, "EOF");

	public static final TokenType COMMENT = new TokenType(16, "COMMENT");

	public static final TokenType PERCENT = new TokenType(17, "PERCENT");

	public static final TokenType CONDITIONAL = new TokenType(18, "CONDITIONAL");

	public static final TokenType ENDCONDITIONAL = new TokenType(19,
			"ENDCONDITIONAL");

	protected class StreamInfo
	{

		String id;

		Reader in;

		int lineNumber = 1;

		int column = 1;

		StreamInfo(String id, Reader in)
		{
			this.id = id;
			this.in = in;
		}
	};

	protected StreamInfo in;

	protected Stack inputStreams;

	protected Token nextToken;

	protected int nextChar;

	protected boolean atEOF;

	protected char[] expandBuffer;

	protected int expandPos;

	protected Hashtable entityExpansion;

	// protected EntityExpansion expander;

	public Scanner(Reader inReader)
	{
		this(inReader, false);
	}

	public Scanner(Reader inReader, boolean doTrace)
	{
		in = new StreamInfo("", inReader);
		atEOF = false;
		expandBuffer = null;
		entityExpansion = new Hashtable();
		// expander = anExpander;
	}

	public Token peek() throws IOException
	{
		if (nextToken == null)
		{
			nextToken = readNextToken();
		}

		return nextToken;
	}

	public Token get() throws IOException
	{
		if (nextToken == null)
		{
			nextToken = readNextToken();
		}

		Token retval = nextToken;
		nextToken = null;

		return retval;
	}

	protected int readNextChar() throws IOException
	{
		// if (in != null)
		// {
		// System.out.println("cunzai ");
		// }
		// if (in.in != null)
		// {
		// System.out.println("cunzai cunzai");
		// }
		int ch = in.in.read();
		if (ch < 0)
		{
			if ((inputStreams != null) && (!inputStreams.empty()))
			{
				in.in.close();
				in = (StreamInfo) inputStreams.pop();
				return readNextChar();
			}
		}
		return ch;
	}

	protected int peekChar() throws IOException
	{
		if (expandBuffer != null)
		{
			return (int) expandBuffer[expandPos];
		}

		if (nextChar == 0)
		{
			nextChar = readNextChar();
			in.column++;
			if (nextChar == '\n')
			{
				in.lineNumber++;
				in.column = 1;
			}
		}

		return nextChar;
	}

	protected int read() throws IOException
	{
		if (expandBuffer != null)
		{
			int expNextChar = expandBuffer[expandPos++];
			if (expandPos >= expandBuffer.length)
			{
				expandPos = -1;
				expandBuffer = null;
			}

			// System.out.print((char) expNextChar);

			return expNextChar;
		}
		if (nextChar == 0)
		{
			peekChar();
		}

		int retval = nextChar;
		nextChar = 0;

		// System.out.print((char) retval);

		return retval;
	}

	public String getUntil(char stopChar) throws IOException
	{
		StringBuffer out = new StringBuffer();

		int ch;

		while ((ch = read()) >= 0)
		{
			if (ch == stopChar)
			{
				return out.toString();
			}
			out.append((char) ch);
		}
		return out.toString();
	}

	public void skipUntil(char stopChar) throws IOException
	{
		int ch;

		while ((ch = read()) >= 0)
		{
			if (ch == stopChar)
			{
				return;
			}
		}
		return;
	}

	protected Token readNextToken() throws IOException
	{
		for (;;)
		{
			int ch = read();

			if (ch == '<')
			{
				ch = peekChar();
				if (ch == '!')
				{
					read();

					if (peekChar() == '[')
					{
						read();

						return new Token(CONDITIONAL);
					}

					if (peekChar() != '-')
					{
						return new Token(LTBANG);
					} else
					{
						read();
						if (peekChar() != '-')
						{
							throw new IOException();
						}
						read();

						StringBuffer buff = new StringBuffer();
						for (;;)
						{
							if (peekChar() < 0)
							{
								throw new IOException();
							}

							if (peekChar() != '-')
							{
								buff.append((char) read());
							} else
							{
								read();
								if (peekChar() < 0)
								{
									throw new IOException();
								}
								if (peekChar() == '-')
								{
									read();
									if (peekChar() != '>')
									{
										throw new IOException();
									}
									read();
									return new Token(COMMENT, buff.toString());
								} else
								{
									buff.append('-');
								}
							}
						}
					}
				} else if (ch == '?')
				{
					read();
					return new Token(LTQUES);
				} else
				{
					return new Token(LT);
				}
			} else if (ch == '?')
			{
				// Need to treat ?> as two separate tokens because
				// <!ELEMENT blah (foo)?> needs the ? as a QUES, not QUESGT
				/*
				 * ch = peekChar();
				 * 
				 * if (ch == '>') { read(); return new Token(QUESGT); } else {
				 * return new Token(QUES); }
				 */
				return new Token(QUES);
			} else if ((ch == '"') || (ch == '\''))
			{
				int quoteChar = ch;

				StringBuffer buff = new StringBuffer();
				while (peekChar() != quoteChar)
				{
					ch = read();
					if (ch == '\\')
					{
						buff.append((char) read());
					} else if (ch < 0)
					{
						break; // IF EOF before getting end quote
					} else
					{
						buff.append((char) ch);
					}
				}
				read();
				return new Token(STRING, buff.toString());
			} else if (ch == '(')
			{
				return new Token(LPAREN);
			} else if (ch == ')')
			{
				return new Token(RPAREN);
			} else if (ch == '|')
			{
				return new Token(PIPE);
			} else if (ch == '>')
			{
				return new Token(GT);
			} else if (ch == '=')
			{
				return new Token(EQUAL);
			} else if (ch == '*')
			{
				return new Token(ASTERISK);
			} else if (ch == ']')
			{
				if (read() != ']')
				{
					throw new IOException();
				}
				if (read() != '>')
				{
					throw new IOException();
				}

				return new Token(ENDCONDITIONAL);
			} else if (ch == '#')
			{
				StringBuffer buff = new StringBuffer();
				buff.append((char) ch);

				if (isIdentifierChar((char) peekChar()))
				{
					buff.append((char) read());

					while (isNameChar((char) peekChar()))
					{
						buff.append((char) read());
					}
				}
				return new Token(IDENTIFIER, buff.toString());
			} else if ((ch == '&') || (ch == '%'))
			{
				if ((ch == '%') && Character.isWhitespace((char) peekChar()))
				{
					return new Token(PERCENT);
				}

				boolean peRef = (ch == '%');

				StringBuffer buff = new StringBuffer();
				buff.append((char) ch);

				if (isIdentifierChar((char) peekChar()))
				{
					buff.append((char) read());
					while (isNameChar((char) peekChar()))
					{
						buff.append((char) read());
					}
				}

				if (read() != ';')
				{
					throw new IOException();
				}
				buff.append(';');

				if (peRef)
				{
					if (expandEntity(buff.toString()))
					{
						continue;
					} else
					{
						// MAW: Added version 1.17
						// If the entity can't be expanded, don't return it,
						// skip it
						continue;
					}
				}
				return new Token(IDENTIFIER, buff.toString());
			} else if (ch == '+')
			{
				return new Token(PLUS);
			} else if (ch == ',')
			{
				return new Token(COMMA);
			} else if (isIdentifierChar((char) ch))
			{
				StringBuffer buff = new StringBuffer();
				buff.append((char) ch);

				while (isNameChar((char) peekChar()))
				{
					buff.append((char) read());
				}
				return new Token(IDENTIFIER, buff.toString());
			} else if (isNameChar((char) ch))
			{
				StringBuffer buff = new StringBuffer();
				buff.append((char) ch);

				while (isNameChar((char) peekChar()))
				{
					buff.append((char) read());
				}
				// return new Token(NMTOKEN, buff.toString());
			} else if (ch < 0)
			{
				if (atEOF)
				{
					throw new IOException("Read past EOF");
				}
				atEOF = true;
				return new Token(EOF);
			} else if (Character.isWhitespace((char) ch))
			{
				continue;
			} else
			{
				throw new IOException();
			}
		}
	}

	public void skipConditional() throws IOException
	{
		// BEGIN CHANGE
		int ch = 0;
		int nestingDepth = 0; // Add nestingDepth parameter

		for (;;)
		{
			if (ch != ']')
			{
				ch = read();
			}
			if (ch == ']')
			{
				ch = read();
				if (ch == ']')
				{
					ch = read();
					if (ch == '>')
					{
						if (nestingDepth == 0)
						{
							// The end of the IGNORE conditional section
							break;
						} else
						{
							// We are within an ignoreSectContents section.
							// Decrement
							// the nesting depth to represent that this section
							// has
							// been ended.
							nestingDepth--;
						}
					}
				}
			}
			// See if this is the first character of the beginning of a new
			// section.
			if (ch == '<')
			{
				ch = read();
				if (ch == '!')
				{
					ch = read();
					if (ch == '[')
					{
						// The beginning of a new ignoreSectContents section
						// has been found. crement nesting depth.
						nestingDepth++;
					}
				}
			}
		}
		// END CHANGE
	}

	public String getUriId()
	{
		return (in.id);
	}

	public int getLineNumber()
	{
		return in.lineNumber;
	}

	public int getColumn()
	{
		return in.column;
	}

	public boolean isIdentifierChar(char ch)
	{
		if (isLetter(ch) || (ch == '_') || (ch == ':'))
		{
			return true;
		}
		return false;
	}

	public boolean isNameChar(char ch)
	{
		if (isLetter(ch) || isDigit(ch) || (ch == '-') || (ch == '_')
				|| (ch == '.') || (ch == ':') || isCombiningChar(ch)
				|| isExtender(ch))
		{
			return true;
		}
		return false;
	}

	public boolean isLetter(char ch)
	{
		return isBaseChar(ch) || isIdeographic(ch);
	}

	public boolean isBaseChar(char ch)
	{
		for (int i = 0; i < letterRanges.length; i++)
		{
			if (ch < letterRanges[i][0])
				return false;
			if ((ch >= letterRanges[i][0]) && (ch <= letterRanges[i][1]))
				return true;
		}
		return false;
	}

	public boolean isIdeographic(char ch)
	{
		if (ch < 0x4e00)
			return false;
		if ((ch >= 0x4e00) && (ch <= 0x9fa5))
			return true;
		if (ch == 0x3007)
			return true;
		if ((ch >= 0x3021) && (ch <= 0x3029))
			return true;
		return false;
	}

	public boolean isDigit(char ch)
	{
		if ((ch >= 0x0030) && (ch <= 0x0039))
			return true;
		if (ch < 0x0660)
			return false;
		if ((ch >= 0x0660) && (ch <= 0x0669))
			return true;
		if (ch < 0x06f0)
			return false;
		if ((ch >= 0x06f0) && (ch <= 0x06f9))
			return true;
		if (ch < 0x0966)
			return false;
		if ((ch >= 0x0966) && (ch <= 0x096f))
			return true;
		if (ch < 0x09e6)
			return false;
		if ((ch >= 0x09e6) && (ch <= 0x09ef))
			return true;
		if (ch < 0x0a66)
			return false;
		if ((ch >= 0x0a66) && (ch <= 0x0a6f))
			return true;
		if (ch < 0x0ae6)
			return false;
		if ((ch >= 0x0ae6) && (ch <= 0x0aef))
			return true;
		if (ch < 0x0b66)
			return false;
		if ((ch >= 0x0b66) && (ch <= 0x0b6f))
			return true;
		if (ch < 0x0be7)
			return false;
		if ((ch >= 0x0be7) && (ch <= 0x0bef))
			return true;
		if (ch < 0x0c66)
			return false;
		if ((ch >= 0x0c66) && (ch <= 0x0c6f))
			return true;
		if (ch < 0x0ce6)
			return false;
		if ((ch >= 0x0ce6) && (ch <= 0x0cef))
			return true;
		if (ch < 0x0d66)
			return false;
		if ((ch >= 0x0d66) && (ch <= 0x0d6f))
			return true;
		if (ch < 0x0e50)
			return false;
		if ((ch >= 0x0e50) && (ch <= 0x0e59))
			return true;
		if (ch < 0x0ed0)
			return false;
		if ((ch >= 0x0ed0) && (ch <= 0x0ed9))
			return true;
		if (ch < 0x0f20)
			return false;
		if ((ch >= 0x0f20) && (ch <= 0x0f29))
			return true;
		return false;
	}

	public boolean isCombiningChar(char ch)
	{
		if (ch < 0x0300)
			return false;
		if ((ch >= 0x0300) && (ch <= 0x0345))
			return true;
		if ((ch >= 0x0360) && (ch <= 0x0361))
			return true;
		if ((ch >= 0x0483) && (ch <= 0x0486))
			return true;
		if ((ch >= 0x0591) && (ch <= 0x05a1))
			return true;
		if ((ch >= 0x05a3) && (ch <= 0x05b9))
			return true;
		if ((ch >= 0x05bb) && (ch <= 0x05bd))
			return true;
		if (ch == 0x05bf)
			return true;
		if ((ch >= 0x05c1) && (ch <= 0x05c2))
			return true;
		if (ch == 0x05c4)
			return true;
		if ((ch >= 0x064b) && (ch <= 0x0652))
			return true;
		if (ch == 0x0670)
			return true;
		if ((ch >= 0x06d6) && (ch <= 0x06dc))
			return true;
		if ((ch >= 0x06dd) && (ch <= 0x06df))
			return true;
		if ((ch >= 0x06e0) && (ch <= 0x06e4))
			return true;
		if ((ch >= 0x06e7) && (ch <= 0x06e8))
			return true;
		if ((ch >= 0x06ea) && (ch <= 0x06ed))
			return true;
		if ((ch >= 0x0901) && (ch <= 0x0903))
			return true;
		if (ch == 0x093c)
			return true;
		if ((ch >= 0x093e) && (ch <= 0x094c))
			return true;
		if (ch == 0x094d)
			return true;
		if ((ch >= 0x0951) && (ch <= 0x0954))
			return true;
		if ((ch >= 0x0962) && (ch <= 0x0963))
			return true;
		if ((ch >= 0x0981) && (ch <= 0x0983))
			return true;
		if (ch == 0x09bc)
			return true;
		if (ch == 0x09be)
			return true;
		if (ch == 0x09bf)
			return true;
		if ((ch >= 0x09c0) && (ch <= 0x09c4))
			return true;
		if ((ch >= 0x09c7) && (ch <= 0x09c8))
			return true;
		if ((ch >= 0x09cb) && (ch <= 0x09cd))
			return true;
		if (ch == 0x09d7)
			return true;
		if ((ch >= 0x09e2) && (ch <= 0x09e3))
			return true;
		if (ch == 0x0a02)
			return true;
		if (ch == 0x0a3c)
			return true;
		if (ch == 0x0a3e)
			return true;
		if (ch == 0x0a3f)
			return true;
		if ((ch >= 0x0a40) && (ch <= 0x0a42))
			return true;
		if ((ch >= 0x0a47) && (ch <= 0x0a48))
			return true;
		if ((ch >= 0x0a4b) && (ch <= 0x0a4d))
			return true;
		if ((ch >= 0x0a70) && (ch <= 0x0a71))
			return true;
		if ((ch >= 0x0a81) && (ch <= 0x0a83))
			return true;
		if (ch == 0x0abc)
			return true;
		if ((ch >= 0x0abe) && (ch <= 0x0ac5))
			return true;
		if ((ch >= 0x0ac7) && (ch <= 0x0ac9))
			return true;
		if ((ch >= 0x0acb) && (ch <= 0x0acd))
			return true;
		if ((ch >= 0x0b01) && (ch <= 0x0b03))
			return true;
		if (ch == 0x0b3c)
			return true;
		if ((ch >= 0x0b3e) && (ch <= 0x0b43))
			return true;
		if ((ch >= 0x0b47) && (ch <= 0x0b48))
			return true;
		if ((ch >= 0x0b4b) && (ch <= 0x0b4d))
			return true;
		if ((ch >= 0x0b56) && (ch <= 0x0b57))
			return true;
		if ((ch >= 0x0b82) && (ch <= 0x0b83))
			return true;
		if ((ch >= 0x0bbe) && (ch <= 0x0bc2))
			return true;
		if ((ch >= 0x0bc6) && (ch <= 0x0bc8))
			return true;
		if ((ch >= 0x0bca) && (ch <= 0x0bcd))
			return true;
		if (ch == 0x0bd7)
			return true;
		if ((ch >= 0x0c01) && (ch <= 0x0c03))
			return true;
		if ((ch >= 0x0c3e) && (ch <= 0x0c44))
			return true;
		if ((ch >= 0x0c46) && (ch <= 0x0c48))
			return true;
		if ((ch >= 0x0c4a) && (ch <= 0x0c4d))
			return true;
		if ((ch >= 0x0c55) && (ch <= 0x0c56))
			return true;
		if ((ch >= 0x0c82) && (ch <= 0x0c83))
			return true;
		if ((ch >= 0x0cbe) && (ch <= 0x0cc4))
			return true;
		if ((ch >= 0x0cc6) && (ch <= 0x0cc8))
			return true;
		if ((ch >= 0x0cca) && (ch <= 0x0ccd))
			return true;
		if ((ch >= 0x0cd5) && (ch <= 0x0cd6))
			return true;
		if ((ch >= 0x0d02) && (ch <= 0x0d03))
			return true;
		if ((ch >= 0x0d3e) && (ch <= 0x0d43))
			return true;
		if ((ch >= 0x0d46) && (ch <= 0x0d48))
			return true;
		if ((ch >= 0x0d4a) && (ch <= 0x0d4d))
			return true;
		if (ch == 0x0d57)
			return true;
		if (ch == 0x0e31)
			return true;
		if ((ch >= 0x0e34) && (ch <= 0x0e3a))
			return true;
		if ((ch >= 0x0e47) && (ch <= 0x0e4e))
			return true;
		if (ch == 0x0eb1)
			return true;
		if ((ch >= 0x0eb4) && (ch <= 0x0eb9))
			return true;
		if ((ch >= 0x0ebb) && (ch <= 0x0ebc))
			return true;
		if ((ch >= 0x0ec8) && (ch <= 0x0ecd))
			return true;
		if ((ch >= 0x0f18) && (ch <= 0x0f19))
			return true;
		if (ch == 0x0f35)
			return true;
		if (ch == 0x0f37)
			return true;
		if (ch == 0x0f39)
			return true;
		if (ch == 0x0f3e)
			return true;
		if (ch == 0x0f3f)
			return true;
		if ((ch >= 0x0f71) && (ch <= 0x0f84))
			return true;
		if ((ch >= 0x0f86) && (ch <= 0x0f8b))
			return true;
		if ((ch >= 0x0f90) && (ch <= 0x0f95))
			return true;
		if (ch == 0x0f97)
			return true;
		if ((ch >= 0x0f99) && (ch <= 0x0fad))
			return true;
		if ((ch >= 0x0fb1) && (ch <= 0x0fb7))
			return true;
		if (ch == 0x0fb9)
			return true;
		if ((ch >= 0x20d0) && (ch <= 0x20dc))
			return true;
		if (ch == 0x20e1)
			return true;
		if ((ch >= 0x302a) && (ch <= 0x302f))
			return true;
		if (ch == 0x3099)
			return true;
		if (ch == 0x309a)
			return true;

		return false;
	}

	public boolean isExtender(char ch)
	{
		if (ch < 0x00b7)
			return false;

		if ((ch == 0x00b7) || (ch == 0x02d0) || (ch == 0x02d1)
				|| (ch == 0x0387) || (ch == 0x0640) || (ch == 0x0e46)
				|| ((ch >= 0x3031) && (ch <= 0x3035))
				|| ((ch >= 0x309d) && (ch <= 0x309e))
				|| ((ch >= 0x30fc) && (ch <= 0x30fe)))
			return true;

		return false;
	}

	public boolean expandEntity(String entityName) throws IOException
	{
		String entity = (String) entityExpansion.get(entityName);
		if (entity != null)
		{
			expand(entity.toCharArray());
			return true;
		}

		entityName = entityName.substring(1, entityName.length() - 1);

		if (inputStreams == null)
		{
			inputStreams = new Stack();
		}

		inputStreams.push(in);

		return true;

	}

	public void expand(char[] expandChars)
	{
		if (expandBuffer != null)
		{
			int oldCharsLeft = expandBuffer.length - expandPos;

			char[] newExp = new char[oldCharsLeft + expandChars.length];
			System.arraycopy(expandChars, 0, newExp, 0, expandChars.length);
			System.arraycopy(expandBuffer, expandPos, newExp,
					expandChars.length, oldCharsLeft);
			expandPos = 0;
			expandBuffer = newExp;
			if (expandBuffer.length == 0)
			{
				expandBuffer = null;
				expandPos = -1;
			}
		} else
		{
			expandBuffer = expandChars;
			expandPos = 0;
			if (expandBuffer.length == 0)
			{
				expandBuffer = null;
				expandPos = -1;
			}
		}
	}

	public void addEntity(String entityName, String entityValue)
	{
		entityExpansion.put("%" + entityName + ";", entityValue);
	}

	public static char letterRanges[][] =
	{
	{ 0x0041, 0x005A },
	{ 0x0061, 0x007A },
	{ 0x00C0, 0x00D6 },
	{ 0x00D8, 0x00F6 },
	{ 0x00F8, 0x00FF },
	{ 0x0100, 0x0131 },
	{ 0x0134, 0x013E },
	{ 0x0141, 0x0148 },
	{ 0x014A, 0x017E },
	{ 0x0180, 0x01C3 },
	{ 0x01CD, 0x01F0 },
	{ 0x01F4, 0x01F5 },
	{ 0x01FA, 0x0217 },
	{ 0x0250, 0x02A8 },
	{ 0x02BB, 0x02C1 },
	{ 0x0386, 0x0386 },
	{ 0x0388, 0x038A },
	{ 0x038C, 0x038C },
	{ 0x038E, 0x03A1 },
	{ 0x03A3, 0x03CE },
	{ 0x03D0, 0x03D6 },
	{ 0x03DA, 0x03DA },
	{ 0x03DC, 0x03DC },
	{ 0x03DE, 0x03DE },
	{ 0x03E0, 0x03E0 },
	{ 0x03E2, 0x03F3 },
	{ 0x0401, 0x040C },
	{ 0x040E, 0x044F },
	{ 0x0451, 0x045C },
	{ 0x045E, 0x0481 },
	{ 0x0490, 0x04C4 },
	{ 0x04C7, 0x04C8 },
	{ 0x04CB, 0x04CC },
	{ 0x04D0, 0x04EB },
	{ 0x04EE, 0x04F5 },
	{ 0x04F8, 0x04F9 },
	{ 0x0531, 0x0556 },
	{ 0x0559, 0x0559 },
	{ 0x0561, 0x0586 },
	{ 0x05D0, 0x05EA },
	{ 0x05F0, 0x05F2 },
	{ 0x0621, 0x063A },
	{ 0x0641, 0x064A },
	{ 0x0671, 0x06B7 },
	{ 0x06BA, 0x06BE },
	{ 0x06C0, 0x06CE },
	{ 0x06D0, 0x06D3 },
	{ 0x06D5, 0x06D5 },
	{ 0x06E5, 0x06E6 },
	{ 0x0905, 0x0939 },
	{ 0x093D, 0x093D },
	{ 0x0958, 0x0961 },
	{ 0x0985, 0x098C },
	{ 0x098F, 0x0990 },
	{ 0x0993, 0x09A8 },
	{ 0x09AA, 0x09B0 },
	{ 0x09B2, 0x09B2 },
	{ 0x09B6, 0x09B9 },
	{ 0x09DC, 0x09DD },
	{ 0x09DF, 0x09E1 },
	{ 0x09F0, 0x09F1 },
	{ 0x0A05, 0x0A0A },
	{ 0x0A0F, 0x0A10 },
	{ 0x0A13, 0x0A28 },
	{ 0x0A2A, 0x0A30 },
	{ 0x0A32, 0x0A33 },
	{ 0x0A35, 0x0A36 },
	{ 0x0A38, 0x0A39 },
	{ 0x0A59, 0x0A5C },
	{ 0x0A5E, 0x0A5E },
	{ 0x0A72, 0x0A74 },
	{ 0x0A85, 0x0A8B },
	{ 0x0A8D, 0x0A8D },
	{ 0x0A8F, 0x0A91 },
	{ 0x0A93, 0x0AA8 },
	{ 0x0AAA, 0x0AB0 },
	{ 0x0AB2, 0x0AB3 },
	{ 0x0AB5, 0x0AB9 },
	{ 0x0ABD, 0x0ABD },
	{ 0x0AE0, 0x0AE0 },
	{ 0x0B05, 0x0B0C },
	{ 0x0B0F, 0x0B10 },
	{ 0x0B13, 0x0B28 },
	{ 0x0B2A, 0x0B30 },
	{ 0x0B32, 0x0B33 },
	{ 0x0B36, 0x0B39 },
	{ 0x0B3D, 0x0B3D },
	{ 0x0B5C, 0x0B5D },
	{ 0x0B5F, 0x0B61 },
	{ 0x0B85, 0x0B8A },
	{ 0x0B8E, 0x0B90 },
	{ 0x0B92, 0x0B95 },
	{ 0x0B99, 0x0B9A },
	{ 0x0B9C, 0x0B9C },
	{ 0x0B9E, 0x0B9F },
	{ 0x0BA3, 0x0BA4 },
	{ 0x0BA8, 0x0BAA },
	{ 0x0BAE, 0x0BB5 },
	{ 0x0BB7, 0x0BB9 },
	{ 0x0C05, 0x0C0C },
	{ 0x0C0E, 0x0C10 },
	{ 0x0C12, 0x0C28 },
	{ 0x0C2A, 0x0C33 },
	{ 0x0C35, 0x0C39 },
	{ 0x0C60, 0x0C61 },
	{ 0x0C85, 0x0C8C },
	{ 0x0C8E, 0x0C90 },
	{ 0x0C92, 0x0CA8 },
	{ 0x0CAA, 0x0CB3 },
	{ 0x0CB5, 0x0CB9 },
	{ 0x0CDE, 0x0CDE },
	{ 0x0CE0, 0x0CE1 },
	{ 0x0D05, 0x0D0C },
	{ 0x0D0E, 0x0D10 },
	{ 0x0D12, 0x0D28 },
	{ 0x0D2A, 0x0D39 },
	{ 0x0D60, 0x0D61 },
	{ 0x0E01, 0x0E2E },
	{ 0x0E30, 0x0E30 },
	{ 0x0E32, 0x0E33 },
	{ 0x0E40, 0x0E45 },
	{ 0x0E81, 0x0E82 },
	{ 0x0E84, 0x0E84 },
	{ 0x0E87, 0x0E88 },
	{ 0x0E8A, 0x0E8A },
	{ 0x0E8D, 0x0E8D },
	{ 0x0E94, 0x0E97 },
	{ 0x0E99, 0x0E9F },
	{ 0x0EA1, 0x0EA3 },
	{ 0x0EA5, 0x0EA5 },
	{ 0x0EA7, 0x0EA7 },
	{ 0x0EAA, 0x0EAB },
	{ 0x0EAD, 0x0EAE },
	{ 0x0EB0, 0x0EB0 },
	{ 0x0EB2, 0x0EB3 },
	{ 0x0EBD, 0x0EBD },
	{ 0x0EC0, 0x0EC4 },
	{ 0x0F40, 0x0F47 },
	{ 0x0F49, 0x0F69 },
	{ 0x10A0, 0x10C5 },
	{ 0x10D0, 0x10F6 },
	{ 0x1100, 0x1100 },
	{ 0x1102, 0x1103 },
	{ 0x1105, 0x1107 },
	{ 0x1109, 0x1109 },
	{ 0x110B, 0x110C },
	{ 0x110E, 0x1112 },
	{ 0x113C, 0x113C },
	{ 0x113E, 0x113E },
	{ 0x1140, 0x1140 },
	{ 0x114C, 0x114C },
	{ 0x114E, 0x114E },
	{ 0x1150, 0x1150 },
	{ 0x1154, 0x1155 },
	{ 0x1159, 0x1159 },
	{ 0x115F, 0x1161 },
	{ 0x1163, 0x1163 },
	{ 0x1165, 0x1165 },
	{ 0x1167, 0x1167 },
	{ 0x1169, 0x1169 },
	{ 0x116D, 0x116E },
	{ 0x1172, 0x1173 },
	{ 0x1175, 0x1175 },
	{ 0x119E, 0x119E },
	{ 0x11A8, 0x11A8 },
	{ 0x11AB, 0x11AB },
	{ 0x11AE, 0x11AF },
	{ 0x11B7, 0x11B8 },
	{ 0x11BA, 0x11BA },
	{ 0x11BC, 0x11C2 },
	{ 0x11EB, 0x11EB },
	{ 0x11F0, 0x11F0 },
	{ 0x11F9, 0x11F9 },
	{ 0x1E00, 0x1E9B },
	{ 0x1EA0, 0x1EF9 },
	{ 0x1F00, 0x1F15 },
	{ 0x1F18, 0x1F1D },
	{ 0x1F20, 0x1F45 },
	{ 0x1F48, 0x1F4D },
	{ 0x1F50, 0x1F57 },
	{ 0x1F59, 0x1F59 },
	{ 0x1F5B, 0x1F5B },
	{ 0x1F5D, 0x1F5D },
	{ 0x1F5F, 0x1F7D },
	{ 0x1F80, 0x1FB4 },
	{ 0x1FB6, 0x1FBC },
	{ 0x1FBE, 0x1FBE },
	{ 0x1FC2, 0x1FC4 },
	{ 0x1FC6, 0x1FCC },
	{ 0x1FD0, 0x1FD3 },
	{ 0x1FD6, 0x1FDB },
	{ 0x1FE0, 0x1FEC },
	{ 0x1FF2, 0x1FF4 },
	{ 0x1FF6, 0x1FFC },
	{ 0x2126, 0x2126 },
	{ 0x212A, 0x212B },
	{ 0x212E, 0x212E },
	{ 0x2180, 0x2182 },
	{ 0x3041, 0x3094 },
	{ 0x30A1, 0x30FA },
	{ 0x3105, 0x312C },
	{ 0xAC00, 0xD7A3 } };
}
